﻿using DomainService.Service.Sys;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Model.BusinessModel.MatchFormula;
using System.Collections.Generic;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.Json;
using Utility.Enum;

namespace CoreDomain.BusinessCore
{
    /// <summary>
    /// 数据权限核心
    /// </summary>
    public static class DataAuthCore
    {
        //匹配公式字符_英文，用于解析
        private static string matchingFormulaString = string.Empty;
        //匹配公式字符_中文，用于显示
        private static string matchingFormulaString_CN = string.Empty;

        /// <summary>
        /// 预览公式
        /// </summary>
        /// <param name="matchingDataInputs">公式数据</param>
        /// <param name="dataRuleConfigList">数据规则配置</param>
        /// <returns>返回解析好的字符串</returns>
        public static (string, string) PreviewFormula(List<MatchingDataInput> matchingDataInputs, List<SysDataRuleConfig> dataRuleConfigList)
        {
            matchingFormulaString = string.Empty;
            matchingFormulaString_CN = string.Empty;
            var data = GetMatchingFormulaString(matchingDataInputs, dataRuleConfigList);
            return data;
        }

        /// <summary>
        /// 递归匹配公式字符串
        /// </summary>
        /// <param name="matchingDataInputs">公式数据</param>
        /// <param name="dataRuleConfigList">数据规则配置</param>
        /// <returns>返回解析好的字符串</returns>
        private static (string, string) GetMatchingFormulaString(List<MatchingDataInput> matchingDataInputs, List<SysDataRuleConfig> dataRuleConfigList)
        {
            //循环公式数据
            foreach (var item in matchingDataInputs)
            {
                int count = 0;
                matchingFormulaString += "( ";
                matchingFormulaString_CN += "( ";

                //循环匹配条件
                foreach (var input in item.matchingWhere)
                {
                    count++;
                    var matchWhere = string.Empty;
                    var matchWhere_CN = string.Empty;
                    var permissionsFieldName = dataRuleConfigList.Where(f => f.PermissionsField == input.fieldKey).FirstOrDefault()?.PermissionsFieldName ?? string.Empty;
                    if (string.IsNullOrWhiteSpace(permissionsFieldName))
                        matchWhere_CN = input.fieldKey + string.Format(" {0} ", input.matchEquationKey);
                    else
                        matchWhere_CN = permissionsFieldName + string.Format(" {0} ", input.matchEquationKey);

                    matchWhere = input.fieldKey + string.Format(" {0} ", input.matchEquationKey);

                    //判断结果类型
                    if (input.showDataControl == (int)ShowControlEnum.Input)
                    {
                        matchWhere += string.Format("\"{0}\"", input.matchDataName);
                        matchWhere_CN += string.Format("\"{0}\"", input.matchDataName);
                    }
                    else if (input.showDataControl == (int)ShowControlEnum.Number)
                    {
                        matchWhere += string.Format("{0}", input.matchDataName);
                        matchWhere_CN += string.Format("{0}", input.matchDataName);
                    }
                    else
                    {
                        matchWhere += string.Format("\"{0}\"", input.matchDataName);
                        matchWhere_CN += string.Format("\"{0}\"", input.matchDataName);
                    }

                    if (item.matchGroup == "And")
                    {
                        if (count > 1)
                        {
                            matchingFormulaString = matchingFormulaString + " && " + matchWhere;
                            matchingFormulaString_CN = matchingFormulaString_CN + " 且 " + matchWhere_CN;
                        }
                        else
                        {
                            matchingFormulaString += matchWhere;
                            matchingFormulaString_CN += matchWhere_CN;
                        }
                    }
                    else
                    {
                        if (count > 1)
                        {
                            matchingFormulaString = matchingFormulaString + " || " + matchWhere;
                            matchingFormulaString_CN = matchingFormulaString_CN + " 或 " + matchWhere_CN;
                        }
                        else
                        {
                            matchingFormulaString += matchWhere;
                            matchingFormulaString_CN += matchWhere_CN;
                        }
                    }
                }

                //是否有子集，无子集根据层级添加括弧
                if (item.children.Count == 0)
                {
                    var kh = string.Empty;
                    for (int i = 0; i < item.level; ++i)
                    {
                        kh += " )";
                    }
                    matchingFormulaString += kh;
                    matchingFormulaString_CN += kh;
                }
                //是否有子集，有子集开始递归
                if (item.children.Count > 0)
                {
                    if (item.matchGroup == "And")
                    {
                        matchingFormulaString += " && ";
                        matchingFormulaString_CN += " 且 ";
                    }
                    else if (item.matchGroup == "Or")
                    {
                        matchingFormulaString += " || ";
                        matchingFormulaString_CN += " 或 ";
                    }
                    GetMatchingFormulaString(item.children, dataRuleConfigList);
                }
            }
            return (matchingFormulaString, matchingFormulaString_CN);

        }

        /// <summary>
        /// 通过数据字典，动态创建模型
        /// </summary>
        /// <param name="dictionary">字典数据</param>
        /// <returns></returns>
        public static Object CreatModel(Dictionary<string, object> dictionary)
        {

            //创建动态代码。
            StringBuilder classSource = new StringBuilder();
            classSource.Append("public class DynamicModel \n");
            classSource.Append("{\n");
            //创建属性。
            foreach (var item in dictionary)
            {
                if (item.Value == null)
                    classSource.Append(" public string " + item.Key + " { get; set; }");
                else
                {
                    var type = item.Value.GetType().Name;
                    if (type == "Int64")
                        type = "long";
                    if (type == "Boolean")
                        type = "bool";
                    if (type == "JArray")
                        type = "object";
                    if (type == "String")
                        type = "string";
                    classSource.Append(" public " + type + " " + item.Key + " { get; set; }");
                }
            }
            classSource.Append("}");

            var syntaxTree = CSharpSyntaxTree.ParseText(classSource.ToString());
            var references = new List<MetadataReference>
                {
                    MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
                };

            var compilation = CSharpCompilation.Create("DynamicModel.dll")
                .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
                .AddReferences(references)
                .AddSyntaxTrees(syntaxTree);
            using var ms = new MemoryStream();
            var result = compilation.Emit(ms);
            if (!result.Success)
            {
                IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
                    diagnostic.IsWarningAsError ||
                    diagnostic.Severity == DiagnosticSeverity.Error);

                foreach (Diagnostic diagnostic in failures)
                {
                    Console.Error.WriteLine("\t" + diagnostic.ToString());
                }
                return null;
            }

            ms.Seek(0, SeekOrigin.Begin);
            Assembly assembly = Assembly.Load(ms.ToArray());
            var dynamicModelType = assembly.GetType("DynamicModel");
            object instance = new();
            if (dynamicModelType != null)
            {
                // 使用动态创建的模型类
                instance = Activator.CreateInstance(dynamicModelType);
                // ...
            }
            foreach (var item in dictionary)
            {
                PropertyInfo _Property = instance.GetType().GetProperty(item.Key);
                if (_Property != null && _Property.CanRead)
                {
                    _Property.SetValue(instance, item.Value, null);
                }
            }
            return instance;
        }

        /// <summary>
        /// 是否拥有按钮权限
        /// </summary>
        /// <param name="model"></param>
        /// <param name="ruleStr"></param>
        /// <returns></returns>
        public static bool IsHaveButtonAuth(object model, string ruleStr)
        {
            try
            {
                //构建模型属性表达式树
                Type aType = model.GetType();
                var dataParameter = Expression.Parameter(aType);
                //执行表达式树
                var expar = DynamicExpressionParser.ParseLambda(new[] { dataParameter }, typeof(bool), ruleStr).Compile();
                var result = Convert.ToBoolean(expar.DynamicInvoke(model));
                return result;
            }
            catch (Exception)
            {
                return false;
            }

        }
    }
}
